#include "BlockQueue.hpp"
#include "Task.h"
#include <ctime>
#include <cstdlib>
#include <memory>
#include <unistd.h>
#include <cassert>

// C -> calculate 计算任务
// S -> save 存储任务
// 用来存储上下文并当参数传递
template<class C, class S>
struct BlockQueues {
    BlockQueue<C>* _calculate_block_queue;
    BlockQueue<S>* _save_block_queue;
};

void* producer(void* block_queues) {
    assert(block_queues);
    BlockQueue<CalculateTask>* calculate_block_queue = (static_cast<BlockQueues<CalculateTask, SaveTask> *>(block_queues))->_calculate_block_queue;

    while (true) {
        int x = rand() % 51 + 50;
        int y = rand() % 21;
        int operator_index = rand() % operators.size();

        CalculateTask task = CalculateTask(x, y, operators[operator_index], calculate);
        cout << "producer thread, 生产计算任务: " << task.showTask() << endl;
        calculate_block_queue->push(move(task));

        sleep(1);
    }

    return nullptr;
}

// consumer既是与producer关系之间的消费者
// 也是与saver关系之间的生产者
void* consumer(void* block_queues) {
    assert(block_queues);
    BlockQueue<CalculateTask>* calculate_block_queue = (static_cast<BlockQueues<CalculateTask, SaveTask>*>(block_queues))->_calculate_block_queue;
    BlockQueue<SaveTask>* save_block_queue = (static_cast<BlockQueues<CalculateTask, SaveTask>*>(block_queues))->_save_block_queue;

    while (true) {
        CalculateTask calculate_task;
        calculate_block_queue->pop(&calculate_task);

        string result = calculate_task();
        cout << "calculate thread, 完成计算任务: " << result << " ... done" << endl;

        save_block_queue->push(SaveTask(result, save));
        cout << "calculate thread, 完成推送存储任务..." << endl; 
    }

    return nullptr;
}

void* saver(void* block_queues) {
    assert(block_queues);
    BlockQueue<SaveTask>* save_block_queue = (static_cast<BlockQueues<CalculateTask, SaveTask>*>(block_queues))->_save_block_queue;

    while (true) {
        SaveTask save_task;
        save_block_queue->pop(&save_task);

        save_task();
        cout << "save thread, 完成存储任务..." << endl;
    }

    return nullptr;
}

int main() {
    srand(static_cast<unsigned int>(time(nullptr)) ^ getpid() | getppid());

    BlockQueues<CalculateTask, SaveTask> block_queues;
    block_queues._calculate_block_queue = new BlockQueue<CalculateTask>();
    block_queues._save_block_queue = new BlockQueue<SaveTask>();

    pthread_t producer_threads[3], calculate_threads[5], save_thread;

    //! 给我记牢了！pthread_create的最后一个参数是传递给执行函数的参数，不是返回值！！！！！！
    //! join的第二个参数才是获取返回值，害我debug了一个小时，看半天才看出空指针了！！！！！！
    for (auto& producer_thread : producer_threads) {
        pthread_create(&producer_thread, nullptr, producer, &block_queues);
    }

    for (auto& calculate_thread : calculate_threads) {
        pthread_create(&calculate_thread, nullptr, consumer, &block_queues);
    }

    pthread_create(&save_thread, nullptr, saver, &block_queues);

    for (auto& producer_thread : producer_threads) {
        pthread_join(producer_thread, nullptr);
    }

    for (auto& calculate_thread : calculate_threads) {
        pthread_join(calculate_thread, nullptr);
    }

    pthread_join(save_thread, nullptr);

    delete block_queues._calculate_block_queue;
    delete block_queues._save_block_queue;

    return 0;
}